using System;
using System.Runtime.CompilerServices;

public class Async2 : INotifyCompletion
{
	public Action Resume { get; private set; }
	int result;

	public Async2()
	{
		Console.WriteLine("2 Async2()");
	}

	public Async2 GetAwaiter() // 每次await都会获取一次
	{
		Console.WriteLine("3 GetAwaiter()");
		return this;
	}

	public bool IsCompleted // 每次await都会判断一次
	{
		get
		{
			Console.WriteLine("4 IsCompleted");
			return result != 0;
		}
	}

	public void OnCompleted(Action c) // 调用IsCompleted=false时设置一次
	{
		Console.WriteLine("5 OnCompleted()");
		Resume = c;
	}

	public int GetResult() // 调用IsCompleted=true时或OnCompleted的Action回调时获取一次
	{
		Console.WriteLine("7 GetResult()");
		return result;
	}

	static async MyTask g(Async2 a)
	{
		int r = await a;
		Console.WriteLine("8, " + r);
		a.result = 0;
		r = await a;
		Console.WriteLine("9, " + r);
	}

	static void Main()
	{
		Console.WriteLine("1 Main()");
		var a = new Async2();
		_ = g(a);
		Console.WriteLine("6 Main()");
		a.result = 1;
		a.Resume();
		Console.WriteLine("10 Main()");
		a.result = 0; // 即使IsCompleted会返回false,回调Action也直接调用GetResult获取结果
		a.Resume();
		Console.WriteLine("11 Main()");
	}
}

[AsyncMethodBuilder(typeof(MyTask))]
public struct MyTask
{
	public static MyTask Create()
	{
		Console.WriteLine("MyTask: Create");
		return default(MyTask);
	}

	public void Start<S>(ref S s) where S : IAsyncStateMachine
	{
		Console.WriteLine("MyTask: Start");
		s.MoveNext();
	}

	public MyTask Task
	{
		get
		{
			Console.WriteLine("MyTask: Task");
			return default(MyTask);
		}
	}

	public void AwaitOnCompleted<A, S>(ref A a, ref S s)
		where A : INotifyCompletion where S : IAsyncStateMachine
	{
		Console.WriteLine("MyTask: AwaitOnCompleted");
		a.OnCompleted(s.MoveNext);
	}

	public void AwaitUnsafeOnCompleted<A, S>(ref A a, ref S s)
		where A : ICriticalNotifyCompletion where S : IAsyncStateMachine
	{
		Console.WriteLine("MyTask: AwaitUnsafeOnCompleted");
		a.OnCompleted(s.MoveNext);
	}

	public void SetStateMachine(IAsyncStateMachine s)
	{
		Console.WriteLine("MyTask: SetStateMachine");
	}

	public void SetResult()
	{
		Console.WriteLine("MyTask: SetResult");
	}

	public void SetException(Exception e)
	{
		Console.WriteLine("MyTask: SetException");
	}
}

/*
1 Main()
2 Async2()
MyTask: Create
MyTask: Start
3 GetAwaiter()
4 IsCompleted
MyTask: AwaitOnCompleted
5 OnCompleted()
MyTask: Task
6 Main()
7 GetResult()
8, 1
3 GetAwaiter()
4 IsCompleted
MyTask: AwaitOnCompleted
5 OnCompleted()
10 Main()
7 GetResult()
9, 0
MyTask: SetResult
11 Main()
*/
